# # 为类或静态方法提供装饰器
#
# # 为类和静态方法提供装饰器简单，但是要确保装饰器在@classmethod 或@staticmethod之前
# import time
#
# from functools import wraps
#
#
# # A simple decorater
# def timethis(func):
#     @wraps(func)
#     def wrapper(*args, **kwargs):
#         start = time.time()
#         r = func(*args, **kwargs)
#         end = time.time()
#         print(end - start)
#         return r
#
#     return wrapper
#
#
# # class illustrating application of the decorator to different kinds of methods
#
# class Spam:
#     @timethis
#     def instance_method(self, n):
#         print(self, n)
#         while n > 0:
#             n -= 1
#
#     @classmethod
#     @timethis
#     def class_method(cls, n):
#         print(cls, n)
#         while n> 0:
#             n -= 1
#
#     @staticmethod
#     @timethis
#     def static_method(n):
#         print(n)
#         while n >0:
#             n-=1
#
#
# s = Spam()
# s.instance_method(1000)
# Spam.class_method(1000)
# Spam.static_method(1000)


# 装饰器为被包装函数增加参数
# from functools import wraps
#
# def optional_debug(func):
#     @wraps(func)
#     def wrapper(*args, debug=False, **kwargs):
#         if debug:
#             print('Calling', func.__name__)
#         return func(*args, **kwargs)
#     return wrapper
#
#
# @optional_debug
# def spam(a,b,c):
#     print(a,b,c)
#
# spam(1,2,3)
# spam(1,2,3,debug=True)

# from functools import wraps
# import inspect
#
# def optional_debug(func):
#     if 'debug' in inspect.getfullargspec(func):
#         raise TypeError('debug argument already defined')
#
#     @wraps(func)
#     def wrapper(*args, debug=False, **kwargs):
#         if debug:
#             print('Calling', func.__name__)
#         return func(*args, **kwargs)
#
#     sig = inspect.signature(func)
#     parms = list(sig.parameters.values())
#     parms.append(inspect.Parameter('debug', inspect.Parameter.KEYWORD_ONLY, default=False))
#     wrapper.__signature__ = sig.replace(parameters=parms)
#     return wrapper
#
#
# @optional_debug
# def add(x,y):
#     return x+y
#
# print(inspect.signature(add))
# print(add(2, 3))


# 使用装饰器扩充类的功能
# 不使用继承或元类的方式扩充功能
# def log_getattribute(cls):
#     orig_getattribute = cls.__getattribute__
#     def new_getattribute(self, name):
#         print('getting', name)
#         return orig_getattribute(self, name)
#
#     cls.__getattribute__ = new_getattribute
#     return cls
#
# @log_getattribute
# class A:
#     def __init__(self, x):
#         self.x = x
#
#     def spam(self):
#         pass
#
#
# a = A(42)
# a.x
# a.spam()


# 使用元类控制实例的创建
# 1 禁止类创建实例
class NoInstance(type):
    def __call__(self, *args, **kwargs):
        raise TypeError("Cant't instantiate directly")

class Spam(metaclass=NoInstance):
    @staticmethod
    def grok(x):
        print('Spam.grok')


# 实现单例
class Singleton(type):
    def __init__(self, *args, **kwargs):
        self.__instance = None
        super().__init__(*args, **kwargs)

    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super().__call__(*args,**kwargs)
            return self.__instance
        else:
            return self.__instance

class Spam2(metaclass=Singleton):
    def __init__(self):
        print('Creating Spam2')

a = Spam2()
b = Spam2()
print(a is b)